package com.ce.pms.charge.service.impl;

import java.math.BigDecimal;
import java.util.List;
import java.util.Set;

import org.hibernate.proxy.HibernateProxy;
import org.springframework.util.Assert;

import com.ce.pms.base.service.impl.PmsBaseServiceImpl;
import com.ce.pms.charge.dao.IAccountDao;
import com.ce.pms.charge.dao.IPrePaySchDao;
import com.ce.pms.charge.dao.ITransactionDao;
import com.ce.pms.charge.model.AbstractSubAccount;
import com.ce.pms.charge.model.AccountDomain;
import com.ce.pms.charge.model.ChargeAccountDomain;
import com.ce.pms.charge.model.DepositAccountDO;
import com.ce.pms.charge.model.PrePayAccountDomain;
import com.ce.pms.charge.service.IAccountService;
import com.ce.pms.charge.vo.AccountVO;
import com.ce.pms.common.model.SysInfo;
import com.ce.pms.common.model.SysrefcodeDO;
import com.ce.pms.customer.dao.IProRightDao;
import com.ce.pms.customer.model.ProRightDO;
import com.ce.pms.exception.BusinessException;
import com.ce.pms.house.dao.IHouseDao;
import com.ce.pms.house.model.CoalitionHouseDomain;
import com.ce.pms.house.model.HouseDomain;
import com.ce.util.BeanUtil;
import com.ce.util.BlankUtil;

public class AccountServiceImpl extends PmsBaseServiceImpl implements IAccountService {
	private IAccountDao accountDao;

    private IHouseDao houseDao;

    private IPrePaySchDao prePaySchDao;

    private IProRightDao proRightDao;

	/**
	 * 交易dao
	 */
	private ITransactionDao transactionDao;

	/***
	 * 激活帐户
	 */
	public void activeAccount(AccountDomain account) {
		account.setIsActive(SysrefcodeDO.CONSTANTS_DIGITAL_ONE);
		this.accountDao.updateObject(account);
	}

	/**
     * 对给定房间增加一个活动帐户（含所有子帐户）
     *@param house
     * @author Adama Yue
     * @CreateDate:上午10:13:56
     */
	public AccountDomain addAccount(HouseDomain house, ProRightDO proRight,SysInfo sysInfo) {
        AccountDomain account=null;
		try {
			super.checkParameterIsNull("common:parameters_null_exception", house,proRight,sysInfo);
            account = new AccountDomain(house,proRight,SysrefcodeDO.CONSTANTS_DIGITAL_ONE,sysInfo);
            account.checkRequiredField();
            //收费帐户
            ChargeAccountDomain chargeSub = new ChargeAccountDomain();
            chargeSub.setAccount(account);
            //预交款帐户
            PrePayAccountDomain prePaySub = new PrePayAccountDomain();
            prePaySub.setAccount(account);
            //设置默认的预交方案
            prePaySub.setPrePaySch(this.prePaySchDao.getDefaultPrePaySch());
            //押金保证金账户
            DepositAccountDO depositAccount = new DepositAccountDO();
            depositAccount.setAccount(account);
            account.getSubAccounts().add(chargeSub);
            account.getSubAccounts().add(prePaySub);
            account.getSubAccounts().add(depositAccount);
            this.accountDao.saveObject(account);
        } catch(BusinessException be){
        	throw be;
        } catch (Exception e) {
            super.logger.fatal(e.getMessage(), e);
            throw new BusinessException("charge:charge_add_account_exception",BusinessException.FAILURE);
        }
        return account;
	}

	/**
	 * 功能描述:取得给定房间的当前可用帐户,如有管理房未初始化帐户返回空  <br>
	 * @param house 房屋DO，将使用到其中的ID
	 * @return
	 *
	 * Create author: Adama Yue <br>
	 * Create on: 上午10:15:04  <br>
	 * Edit author:付湘辉  <br>
	 * Edit on:2009-1-6    <br>
	 * Why:修改注释     <br>
	 */
	public AccountDomain currentAccount(HouseDomain house) {
		super.checkParameterIsNull(house, "common:parameters_null_exception");
		ProRightDO proRight = this.proRightDao.getEffectiveProRightByHouse(house);
		AccountDomain curA = this.currentAccount(house.getKeyword(), proRight);
		return curA;
	}
	
	/**
	 * 功能描述:取得给定房间ID的当前可用帐户  <br>
	 * @param houseId 房屋ID
	 * @return
	 *
	 * Create author: 付湘辉 <br>
	 * Create on: 2009-1-6  <br>
	 * Edit author:  <br>
	 * Edit on:    <br>
	 * Why:    <br>
	 */
	public AccountDomain getCurrentAccount(Long houseId) {
		Assert.notNull(houseId);
		ProRightDO proRight = this.proRightDao.getEffectiveProRightByHouseId(houseId);
		AccountDomain curAccount = this.currentAccount(houseId, proRight);
		return curAccount;
	}

    /**
	 * 功能描述: 查询指定产权的房屋当前有效帐户  <br>
	 * @param houseId 房屋id，不论管理房和产权房
	 * @param proRight 产权
	 * @return
	 *
	 * Create author: 付湘辉 <br>
	 * Create on:  <br>
	 * Edit author:2008-8-26 <br>
	 * Edit on:    <br>
	 * Why:     <br>
	 */
	public AccountDomain currentAccount(Long houseId,ProRightDO proRight) {
		Assert.notNull(houseId);
		if (BlankUtil.isBlank(proRight)) {
			return null;
		}
		if (SysrefcodeDO.CONSTANTS_DIGITAL_ZERO.equals(proRight.getChargeSelect())) {//合并记账
			HouseDomain house = proRight.getHouse();
			if (HibernateProxy.class.isInstance(house) ) {
				HibernateProxy  objProxy=(HibernateProxy)house;
				house = (HouseDomain)objProxy.getHibernateLazyInitializer().getImplementation();
			}
			if (!(house instanceof CoalitionHouseDomain)){
				CoalitionHouseDomain cHouse = this.houseDao.getCoalition(this.houseDao.findById(houseId));
				if (!BlankUtil.isBlank(cHouse)) {
					houseId = cHouse.getKeyword();
					proRight = this.proRightDao.getEffectiveProRightByHouse(cHouse);
					if (BlankUtil.isBlank(proRight)) {
						return null;
					}
				}
			}
		}
		
		
		return this.accountDao.getAccountBy(proRight.getProRightId(), houseId,true);
	}

	/**
	 * 功能描述: 物理删除一个产权房的总账，
	 * <b>注意</b>：这个总账应没有产生任何费用。 <br>
	 * @param houseId 产权房id
	 * @return 暂不起作用，只作预留
	 *
	 * Create author:付湘辉 <br>
	 * Create on:2008-10-23  <br>
	 * Edit author:  <br>
	 * Edit on:    <br>
	 * Why:     <br>
	 */
	public Boolean deleteAccountByHouseId(Long houseId){
		ProRightDO proRight = this.proRightDao.getEffectiveProRightByHouseId(houseId);
		if (BlankUtil.isBlank(proRight)) {
			return true;
		}
		AccountDomain account =  this.currentAccount(houseId, proRight);
		if (BlankUtil.isBlank(account)) {
			return true;
		}
		try {
			this.accountDao.deleteObject(account);
		} catch (Exception e) {
			throw new BusinessException("charge:charge_account_not_delete_exception",
						BusinessException.WARNING);
		}
		return true;
	}

	/**
	 * 禁用帐户(前提是余额为零,否则抛异常)
	 *@param house
	 *@param proRight
	 * @author Adama Yue
	 * @CreateDate:下午02:22:52
	 */
	public void disableAccount(AccountDomain account) {
		super.checkParameterIsNull(account, "common:parameters_null_exception ");
		Set<AbstractSubAccount> set = account.getSubAccounts();
		for (AbstractSubAccount account2 : set) {
			if (BigDecimal.ZERO.compareTo(account2.getBalance()) != 0) {
				throw new BusinessException("charge:charge_account_balance_not_zero_exception",
											BusinessException.WARNING);
			}
		}
		account.setIsActive(SysrefcodeDO.CONSTANTS_DIGITAL_ZERO);
		this.accountDao.updateObject(account);
	}

	/**
	 * 功能描述: 得到指定产权和房屋帐户，
	 * 参数isActive如果为true，则只查询其有效账户，否则全都查询   <br>
	 * @param proRightId 产权id
	 * @param houseId 房屋id，不论管理房和产权房
	 * @param isActive
	 * @return
	 *
	 * Create author:付湘辉 <br>
	 * Create on:2008-8-26  <br>
	 * Edit author:  <br>
	 * Edit on:    <br>
	 * Why:     <br>
	 */
	public AccountVO getAccountByProRightAndHouse(Long proRightId,Long houseId,boolean isActive){
		AccountDomain accDo = this.accountDao.getAccountBy(proRightId, houseId,isActive);
		return this.assembleD2V(accDo);
	}

	/**
	 * 功能描述: 根据id查询总账户实体 <br>
	 * @param accountId
	 * @return
	 *
	 * Create author:付湘辉 <br>
	 * Create on:2008-9-5  <br>
	 * Edit author:  <br>
	 * Edit on:    <br>
	 * Why:     <br>
	 */
	public AccountDomain getAccountDoById(Long accountId){
		Assert.notNull(accountId);
		return this.accountDao.findById(accountId);
	}

	/**
	 * 取得给定房间当前帐户的余额，(所有子账户的余额绝对值之和)
	 *@param house
	 *@return
	 * @author Adama Yue
	 * @CreateDate:上午10:09:52
	 */
	public BigDecimal getBalance(HouseDomain house) {
		AccountDomain account = this.currentAccount(house);
		if (BlankUtil.isBlank(account)) {
			return null;
		}
		Set<AbstractSubAccount> set = account.getSubAccounts();
		BigDecimal balance = BigDecimal.valueOf(000l,2);
		//所有子账户的余额绝对值相加得出总和
		for (AbstractSubAccount sub : set) {
			balance = balance.add(sub.getBalance().abs());
		}

		return balance;
	}

	/**
	 * 功能描述: 查询指定房屋id的账户余额（所有子账户的余额绝对值之和） <br>
	 * @param houseId
	 * @return
	 *
	 * Create author:付湘辉 <br>
	 * Create on:2008-9-10  <br>
	 * Edit author:  <br>
	 * Edit on:    <br>
	 * Why:     <br>
	 */
	public BigDecimal getBalance(Long houseId) {
		HouseDomain house = this.houseDao.findById(houseId);
		return this.getBalance(house);
	}

	/**
	 * 功能描述: 查询指定总账户id的物业费用子账的余额 <br>
	 * @param accountId
	 * @return
	 *
	 * Create author:付湘辉 <br>
	 * Create on:2008-9-17  <br>
	 * Edit author:  <br>
	 * Edit on:    <br>
	 * Why:     <br>
	 */
	public BigDecimal getChargeAccountBalance(Long accountId) {
		return this.getSubAccountBalance(accountId, ChargeAccountDomain.class);
	}

	/**
	 * 功能描述: 查询指定总账的收费子账户实体 <br>
	 * @param accountDo
	 * @return
	 *
	 * Create author:付湘辉 <br>
	 * Create on:2008-10-24  <br>
	 * Edit author:  <br>
	 * Edit on:    <br>
	 * Why:     <br>
	 */
	public ChargeAccountDomain getChargeAccountByAccount(AccountDomain accountDo){
		super.checkParameterIsNull(accountDo, "common:parameters_null_exception, ");
		Set<AbstractSubAccount> subSet = accountDo.getSubAccounts();
		for (AbstractSubAccount account : subSet) {
			if (account instanceof ChargeAccountDomain) {
				return (ChargeAccountDomain)account;
			}
		}
		return null;
	}

	/**
	 * 功能描述: 查询指定总账的押金子账户实体 <br>
	 * @param accountDo
	 * @return
	 *
	 * Create author:付湘辉 <br>
	 * Create on:2009-1-8  <br>
	 * Edit author:  <br>
	 * Edit on:    <br>
	 * Why:     <br>
	 */
	public DepositAccountDO getDepositAccountByAccount(AccountDomain accountDo){
		super.checkParameterIsNull(accountDo, "common:parameters_null_exception, ");
		Set<AbstractSubAccount> subSet = accountDo.getSubAccounts();
		for (AbstractSubAccount account : subSet) {
			if (account instanceof DepositAccountDO) {
				return (DepositAccountDO)account;
			}
		}
		return null;
	}

	/**
	 * 功能描述: 查询指定总账id的收费子账户实体 <br>
	 * @param accountId
	 * @return
	 *
	 * Create author:付湘辉 <br>
	 * Create on:2008-10-24  <br>
	 * Edit author:  <br>
	 * Edit on:    <br>
	 * Why:     <br>
	 */
	public ChargeAccountDomain getChargeAccountByAccountId(Long accountId){
		super.checkParameterIsNull(accountId, "common:parameters_null_exception,ID");
		AccountDomain accountDo = this.accountDao.findById(accountId);
		return this.getChargeAccountByAccount(accountDo);
	}
	
	/**
	 * 功能描述: 查询指定总账id的押金子账户实体 <br>
	 * @param accountId
	 * @return
	 *
	 * Create author:付湘辉 <br>
	 * Create on:2008-10-24  <br>
	 * Edit author:  <br>
	 * Edit on:    <br>
	 * Why:     <br>
	 */
	public DepositAccountDO getDepositAccountByAccountId(Long accountId){
		super.checkParameterIsNull(accountId, "common:parameters_null_exception,ID");
		AccountDomain accountDo = this.accountDao.findById(accountId);
		return this.getDepositAccountByAccount(accountDo);
	}

	/**
	 * 功能描述: 得到指定产权和房屋的当前有效帐户  <br>
	 * @param proRightId
	 * @param houseId
	 * @return
	 *
	 * Create author:付湘辉 <br>
	 * Create on:2008-8-26  <br>
	 * Edit author:  <br>
	 * Edit on:    <br>
	 * Why:     <br>
	 */
	public AccountVO getCurrentAccountBy(Long proRightId,Long houseId){
		return this.getAccountByProRightAndHouse(proRightId, houseId, true);
	}

	public List<AccountDomain> getHistoryAccounts(HouseDomain house) {
		// TODO Auto-generated method stub
		return null;
	}

	/**
	 * 功能描述: 查询指定总账户id的预交款子账的余额 <br>
	 * @param accountId
	 * @return
	 *
	 * Create author:付湘辉 <br>
	 * Create on:2008-9-17  <br>
	 * Edit author:  <br>
	 * Edit on:    <br>
	 * Why:     <br>
	 */
	public BigDecimal getPrePayAccountBalance(Long accountId) {
		return this.getSubAccountBalance(accountId, PrePayAccountDomain.class);
	}

	/**
	 * 功能描述: 查询指定总账户id的押金子账户的余额 <br>
	 * @param accountId
	 * @return
	 *
	 * Create author:付湘辉 <br>
	 * Create on:2009-1-8  <br>
	 * Edit author:  <br>
	 * Edit on:    <br>
	 * Why:     <br>
	 */
	public BigDecimal getDepositAccountBalance(Long accountId) {
		return this.getSubAccountBalance(accountId, DepositAccountDO.class);
	}

	/**
	 * 功能描述: 查询指定总账的预交款子账户实体 <br>
	 * @param accountDo
	 * @return
	 *
	 * Create author:付湘辉 <br>
	 * Create on:2008-10-24  <br>
	 * Edit author:  <br>
	 * Edit on:    <br>
	 * Why:     <br>
	 */
	public PrePayAccountDomain getPrePayAccountByAccount(AccountDomain accountDo){
		super.checkParameterIsNull(accountDo, "common:parameters_null_exception, ");
		Set<AbstractSubAccount> subSet = accountDo.getSubAccounts();
		for (AbstractSubAccount account : subSet) {
			if (account instanceof PrePayAccountDomain) {
				return (PrePayAccountDomain)account;
			}
		}
		return null;
	}

	/**
	 * 功能描述: 查询指定总账id的预交款子账户实体 <br>
	 * @param accountId
	 * @return
	 *
	 * Create author:付湘辉 <br>
	 * Create on:2008-10-24  <br>
	 * Edit author:  <br>
	 * Edit on:    <br>
	 * Why:     <br>
	 */
	public PrePayAccountDomain getPrePayAccountByAccountId(Long accountId){
		super.checkParameterIsNull(accountId, "common:parameters_null_exception,ID");
		AccountDomain accountDo = this.accountDao.findById(accountId);
		return this.getPrePayAccountByAccount(accountDo);
	}

	/**
	 * 功能描述: 锁定指定总账户下所有子账户的借货方 <br>
	 * @param accountId
	 * @return
	 *
	 * Create author:付湘辉 <br>
	 * Create on:2008-10-24  <br>
	 * Edit author:  <br>
	 * Edit on:    <br>
	 * Why:     <br>
	 */
	public Boolean lockAccount(Long accountId){
		super.checkParameterIsNull(accountId, "common:parameters_null_exception,ID");
		AccountDomain accountDo = this.accountDao.findById(accountId);
		Set<AbstractSubAccount> subSet = accountDo.getSubAccounts();
		for (AbstractSubAccount account : subSet) {
			account.setLockState(SysrefcodeDO.FEE_ACCOUNT_LOCK_STATE_LOCK_ALL);
		}
		this.accountDao.updateObject(accountDo);
		return true;
	}

	/**
	 * 功能描述: 查询指定的房屋是否产生了费用 <br>
	 * @param house
	 * @return true 产生  false 未产生
	 *
	 * Create author:付湘辉 <br>
	 * Create on:2008-9-1  <br>
	 * Edit author:  <br>
	 * Edit on:    <br>
	 * Why:     <br>
	 */
	public Boolean queryHouseIsProduceCharge(HouseDomain house){
		super.checkParameterIsNull(house, "common:parameters_null_exception, ");
		AccountDomain account = this.currentAccount(house);
		if (BlankUtil.isBlank(account)) {
			return false;
		}

		Long count = this.transactionDao.getTransCountByAccount(account);

		return 0l == count ? false : true;
	}

	public void setAccountDao(IAccountDao accountDao) {
		this.accountDao = accountDao;
	}

	/**
	 * @param houseDao the houseDao to set
	 */
	public void setHouseDao(IHouseDao houseDao) {
		this.houseDao = houseDao;
	}

    /**
     * 功能描述: 设置prePaySchDao
     *
     * @author 付湘辉
     * Created on:2008-8-16
     */
    public void setPrePaySchDao(IPrePaySchDao prePaySchDao) {
        this.prePaySchDao = prePaySchDao;
    }

    /**
	 * @param proRightDao the proRightDao to set
	 */
	public void setProRightDao(IProRightDao proRightDao) {
		this.proRightDao = proRightDao;
	}

	/**
	 * @param transactionDao the transactionDao to set
	 */
	public void setTransactionDao(ITransactionDao transactionDao) {
		this.transactionDao = transactionDao;
	}

	/**
	 * 功能描述: 解锁指定总账户下所有子账户的借货方 <br>
	 * @param accountId
	 * @return
	 *
	 * Create author:付湘辉 <br>
	 * Create on:2008-10-24  <br>
	 * Edit author:  <br>
	 * Edit on:    <br>
	 * Why:     <br>
	 */
	public Boolean unblockAccount(Long accountId){
		AccountDomain accountDo = this.accountDao.findById(accountId);
		Set<AbstractSubAccount> subSet = accountDo.getSubAccounts();
		for (AbstractSubAccount account : subSet) {
			account.setLockState(SysrefcodeDO.FEE_ACCOUNT_LOCK_STATE_NOLOCK);
		}
		this.accountDao.updateObject(accountDo);
		return true;
	}

	/**
	 * 功能描述:  <br>
	 * @param accountdo
	 * @return
	 *
	 * Create author:付湘辉 <br>
	 * Create on:2008-8-25  <br>
	 * Edit author:  <br>
	 * Edit on:    <br>
	 * Why:     <br>
	 */
	private AccountVO assembleD2V(AccountDomain accountdo){
		AccountVO accountVo = null;
		if (!BlankUtil.isBlank(accountdo)) {
			accountVo = new AccountVO();
			BeanUtil.convertVoAsDo(accountdo, accountVo);
			// 房屋
			HouseDomain house = accountdo.getHouse();
			if (!BlankUtil.isBlank(house)) {
				accountVo.setHouseId(house.getKeyword());
			}
			// 产权
			ProRightDO pro = accountdo.getProRight();
			if (!BlankUtil.isBlank(pro)) {
				accountVo.setProRightId(pro.getProRightId());
			}

			SysInfo sysInfo = accountdo.getSysInfo();//得到创建信息和修改信息
			if (!BlankUtil.isBlank(sysInfo)) {
				accountVo.setCreator(sysInfo.getCreator());//创建人id
				accountVo.setSysDate(sysInfo.getSysDate());//创建日期
				accountVo.setModifier(sysInfo.getModifier());//修改人id
				accountVo.setModifierDate(sysInfo.getModifyDate());//修改日期
			}
		}

		return accountVo;
	}

	/**
	 * 功能描述:  <br>
	 * @param accountId
	 * @param clazz
	 * @return
	 *
	 * Create author:付湘辉 <br>
	 * Create on:2008-9-17  <br>
	 * Edit author:  <br>
	 * Edit on:    <br>
	 * Why:     <br>
	 */
	private BigDecimal getSubAccountBalance(Long accountId,Class clazz) {
		AccountDomain account = this.accountDao.findById(accountId);
		Set<AbstractSubAccount> set = account.getSubAccounts();
		//收费子账户的余额
		for (AbstractSubAccount sub : set) {
			if (sub.getClass().equals(clazz)) {
				return sub.getBalance();
			}
		}
		return null;
	}

}
